#pragma once

#include <elf.h>
#include <link.h>

#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>

#define ELF32_CLASS ELFCLASS32
#define ELF64_CLASS ELFCLASS64

enum file_format_t
{
  FILE_FORMAT_UNKNOWN = 0,
  FILE_FORMAT_ELF,
  FILE_FORMAT_PE,
};

/* Type for the buffer we put the ELF header and hopefully the program
   header.  This buffer does not really have to be too large.  In most
   cases the program header follows the ELF header directly.  If this
   is not the case all bets are off and we can make the header
   arbitrarily large and still won't get it read.  This means the only
   question is how large are the ELF and program header combined.  The
   ELF header 32-bit files is 52 bytes long and in 64-bit files is 64
   bytes long.  Each program header entry is again 32 and 56 bytes
   long respectively.  I.e., even with a file which has 10 program
   header entries we only have to read 372B/624B respectively.  Add to
   this a bit of margin for program notes and reading 512B and 832B
   for 32-bit and 64-bit files respecitvely is enough.  If this
   heuristic should really fail for some file the code in
   `_dl_map_object_from_fd' knows how to recover.  */
struct filebuf
{
  enum file_format_t format;
  ssize_t len;
#if __WORDSIZE == 32
# define FILEBUF_SIZE 512
#else
# define FILEBUF_SIZE 832
#endif
  char buf[FILEBUF_SIZE] __attribute__ ((aligned (__alignof (ElfW(Ehdr)))));
};

int is_elf_magic (const char *buf);

int is_pe_magic (const char *buf);

int do_verify_elf (int fd,
                   struct filebuf *fbp, struct link_map *loader,
                   int mode, bool *found_other_class,
                   int *perrval, const char **perrstr);

int do_verify_pe (int fd,
                  struct filebuf *fbp, struct link_map *loader,
                  int mode, bool *found_other_class,
                  int *perrval, const char **perrstr);

int do_load_elf (int fd, struct filebuf *fbp,
                 struct link_map *l, struct link_map *loader, Lmid_t nsid,
                 int mode, void **stack_endp,
                 int *perrval, const char **perrstr);

int do_load_pe (int fd, struct filebuf *fbp,
                struct link_map *l, struct link_map *loader, Lmid_t nsid,
                int mode, void **stack_endp,
                int *perrval, const char **perrstr);
